/**
 * \file   hi_product_statemng_playback.c
 * \brief  Realize the interface about playback state.
 * \author HiMobileCam Reference Develop Team
 * \date   2017/10/19
 */
#include "hi_product_statemng.h"
#include "hi_product_statemng_inner.h"

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* End of #ifdef __cplusplus */

/*Reset part of mediacfg for Playback*/
HI_VOID PDT_STATEMNG_MediaCfgResetForPlayback(HI_PDT_MEDIA_CFG_S* pstMediaCfg)
{
    HI_S32 s32Ret = HI_SUCCESS;
    HI_S32 i = 0, j = 0;
    HI_PDT_WORKMODE_CFG_S stEnterWorkModeCfg;

    for (i = 0; i < HI_PDT_MEDIA_VCAP_DEV_MAX_CNT; i++)
    {
        pstMediaCfg->stVideoCfg.stVcapCfg.astVcapDevAttr[i].bEnable = HI_FALSE;
    }

    /* Not support grp user send frame when vpss working in VI_OFFLINE_VPSS_ONLINE mode */
    for (i = 0; i < HI_PDT_MEDIA_VCAP_DEV_MAX_CNT; i++)
    {
        for (j = 0; j < HI_PDT_MEDIA_VCAPDEV_PIPE_MAX_CNT; j++)
        {
            if (pstMediaCfg->stViVpssMode.astMode[i][j].enMode == VI_OFFLINE_VPSS_ONLINE ||
                pstMediaCfg->stViVpssMode.astMode[i][j].enMode == VI_ONLINE_VPSS_ONLINE)
            {
                pstMediaCfg->stViVpssMode.astMode[i][j].enMode = VI_OFFLINE_VPSS_OFFLINE;
            }
        }
    }

    for (i = 0; i < HI_PDT_MEDIA_VPSS_MAX_CNT; i++)
    {
        pstMediaCfg->stVideoCfg.stVprocCfg.astVpssAttr[i].bEnable = HI_FALSE;

        for (j = 0; j < HI_PDT_MEDIA_VPSS_PORT_MAX_CNT; j++) {
            pstMediaCfg->stVideoCfg.stVprocCfg.astVpssAttr[i].astVportAttr[j].bEnable = HI_FALSE;
        }
        for (j = 0; j < HI_PDT_MEDIA_VPSS_EXTPORT_MAX_CNT; j++) {
            pstMediaCfg->stVideoCfg.stVprocCfg.astVpssAttr[i].extVportAttr[j].enable = HI_FALSE;
        }
    }

    /** get workmode config from Param module */
    memset(&stEnterWorkModeCfg, 0, sizeof(HI_PDT_WORKMODE_CFG_S));
    s32Ret = HI_PDT_PARAM_GetWorkModeCfg(HI_PDT_WORKMODE_PLAYBACK, &stEnterWorkModeCfg);
    PDT_STATEMNG_CHECK_RET_WITH_UNRETURN(s32Ret, "get stEnterWorkModeCfg parameter");
    HI_PDT_PARAM_PLAYBACK_CFG_S*  pstPlayBackCfg = &stEnterWorkModeCfg.unModeCfg.stPlayBackCfg;


    if (HI_LITEPLAYER_VOUT_TYPE_VPSS == pstPlayBackCfg->stVoutOpt.enVoutType)
    {
        HI_BOOL bFound = HI_FALSE;

        for (i = 0; i < HI_PDT_MEDIA_VPSS_MAX_CNT; i++)
        {
            HI_PDT_MEDIA_VPSS_ATTR_S* pstVpssAttr =
                &(pstMediaCfg->stVideoCfg.stVprocCfg.astVpssAttr[i]);
            pstVpssAttr->bEnable = HI_FALSE;

            if (pstVpssAttr->VpssHdl == pstPlayBackCfg->stVoutOpt.hModHdl)
            {
                for (j = 0; j < HI_PDT_MEDIA_VPSS_PORT_MAX_CNT; j++)
                {
                    if (pstVpssAttr->astVportAttr[j].VportHdl == pstPlayBackCfg->stVoutOpt.hChnHdl)
                    {
                        pstVpssAttr->bEnable = HI_TRUE;
                        pstVpssAttr->stVpssAttr.bNrEn = HI_FALSE;
                        pstVpssAttr->stVpssAttr.enPixelFormat = HI_MEDIA_PIXEL_FMT_YVU_SEMIPLANAR_420;
                        pstVpssAttr->astVportAttr[j].bEnable = HI_TRUE;
                        pstVpssAttr->astVportAttr[j].bSupportBufferShare = HI_FALSE;
                        pstVpssAttr->astVportAttr[j].enRotate = ROTATION_0;
                        pstVpssAttr->astVportAttr[j].bFlip = HI_FALSE;
                        pstVpssAttr->astVportAttr[j].bMirror = HI_FALSE;
                        pstVpssAttr->astVportAttr[j].lowDelayInfo.enable = HI_FALSE;
                        pstVpssAttr->stVpssAttr.stFrameRate.s32SrcFrameRate = -1;
                        pstVpssAttr->stVpssAttr.stFrameRate.s32DstFrameRate = -1;
                        bFound = HI_TRUE;
                        break;
                    }
                    else
                    {
                        pstVpssAttr->astVportAttr[j].bEnable = HI_FALSE;
                    }
                }

                if (HI_TRUE == bFound)
                { break; }
            }
        }

        HI_APPCOMM_CHECK_EXPR_WITHOUT_RETURN(HI_TRUE == bFound, "vpss param invald");
    }

#ifdef CONFIG_SCREEN
        HI_HAL_SCREEN_ATTR_S stScreenAttr;
        memset(&stScreenAttr, 0, sizeof(stScreenAttr));
        s32Ret = HI_HAL_SCREEN_GetAttr(HI_HAL_SCREEN_IDX_0, &stScreenAttr);
        HI_APPCOMM_CHECK_EXPR_WITHOUT_RETURN(HI_SUCCESS == s32Ret, "HI_HAL_SCREEN_GetAttr");
#endif

    /** change dispcfg */
    for (i = 0; i < HI_PDT_MEDIA_DISP_MAX_CNT; i++)
    {
        pstMediaCfg->stVideoOutCfg.astDispCfg[i].u32BufferLen = HI_PDT_MEDIA_DISP_VGS_BUFFERLEN;

        pstMediaCfg->stVideoOutCfg.astDispCfg[i].astWndCfg[0].stAspectRatio.enMode = ASPECT_RATIO_NONE;
#ifdef CONFIG_SCREEN
        pstMediaCfg->stVideoOutCfg.astDispCfg[i].astWndCfg[0].stAspectRatio.stVideoRect.s32X = 0;
        pstMediaCfg->stVideoOutCfg.astDispCfg[i].astWndCfg[0].stAspectRatio.stVideoRect.s32Y = 0;
        pstMediaCfg->stVideoOutCfg.astDispCfg[i].astWndCfg[0].stAspectRatio.stVideoRect.u32Width =
            stScreenAttr.stAttr.u32Width;
        pstMediaCfg->stVideoOutCfg.astDispCfg[i].astWndCfg[0].stAspectRatio.stVideoRect.u32Height =
            stScreenAttr.stAttr.u32Height;
        pstMediaCfg->stVideoOutCfg.astDispCfg[i].astWndCfg[0].stWndAttr.stRect.u32Width =
            stScreenAttr.stAttr.u32Width;
        pstMediaCfg->stVideoOutCfg.astDispCfg[i].astWndCfg[0].stWndAttr.stRect.u32Height=
            stScreenAttr.stAttr.u32Height;
        pstMediaCfg->stVideoOutCfg.astDispCfg[i].stImageSize.u32Width =
            stScreenAttr.stAttr.u32Width;
        pstMediaCfg->stVideoOutCfg.astDispCfg[i].stImageSize.u32Height =
            stScreenAttr.stAttr.u32Height;
#endif

#ifdef REARVIEW

        if (ROTATION_90 == pstMediaCfg->stVideoOutCfg.astDispCfg[i].astWndCfg[0].enRotate ||
            ROTATION_270 == pstMediaCfg->stVideoOutCfg.astDispCfg[i].astWndCfg[0].enRotate)
        {
            pstMediaCfg->stVideoOutCfg.astDispCfg[i].astWndCfg[0].stWndAttr.stRect.s32Y =
                pstMediaCfg->stVideoOutCfg.astDispCfg[i].astWndCfg[0].stWndAttr.stRect.u32Height / 2;
            pstMediaCfg->stVideoOutCfg.astDispCfg[i].astWndCfg[0].stWndAttr.stRect.u32Height =
                pstMediaCfg->stVideoOutCfg.astDispCfg[i].astWndCfg[0].stWndAttr.stRect.u32Height / 2 - UI_FILELIST_WINDOW_LEFT_LEN;
        }
        else
        {
            pstMediaCfg->stVideoOutCfg.astDispCfg[i].astWndCfg[0].stWndAttr.stRect.s32X =
                pstMediaCfg->stVideoOutCfg.astDispCfg[i].astWndCfg[0].stWndAttr.stRect.u32Width / 2;
            pstMediaCfg->stVideoOutCfg.astDispCfg[i].astWndCfg[0].stWndAttr.stRect.u32Width =
                pstMediaCfg->stVideoOutCfg.astDispCfg[i].astWndCfg[0].stWndAttr.stRect.u32Width / 2 - UI_FILELIST_WINDOW_LEFT_LEN;
        }

#endif

        HI_PDT_MEDIA_DISP_CFG_S* pstDispCfg =
            &(pstMediaCfg->stVideoOutCfg.astDispCfg[i]);

        if (HI_LITEPLAYER_VOUT_TYPE_VPSS == pstPlayBackCfg->stVoutOpt.enVoutType)
        {
            pstDispCfg->astWndCfg[0].enBindedMod = HI_PDT_MEDIA_VIDEOMOD_VPSS;
            pstDispCfg->astWndCfg[0].ModHdl = pstPlayBackCfg->stVoutOpt.hModHdl;
            pstDispCfg->astWndCfg[0].ChnHdl = pstPlayBackCfg->stVoutOpt.hChnHdl;
        }
        else
        { pstDispCfg->astWndCfg[0].enBindedMod = HI_PDT_MEDIA_VIDEOMOD_DISP; }

        for (i = 0; i < HI_PDT_MEDIA_DISP_WND_MAX_CNT; i++)
        {
            pstDispCfg->astWndCfg[i].stCropCfg.bEnable = HI_FALSE;
        }

        for(i=1;i<HI_PDT_MEDIA_DISP_WND_MAX_CNT;i++)
        {
            pstDispCfg->astWndCfg[i].bEnable = HI_FALSE; /* only open first vo_wnd in playback mode */
        }

    }

#if !defined(HI3518EV300)
    pstMediaCfg->stVBCfg.u32MaxPoolCnt = 1;
    pstMediaCfg->stVBCfg.astCommPool[0].u32BlkCnt = 5;
    pstMediaCfg->stVBCfg.astCommPool[0].u32BlkSize = pstMediaCfg->stVideoOutCfg.astDispCfg[0].astWndCfg[0].stWndAttr.stRect.u32Height *
        pstMediaCfg->stVideoOutCfg.astDispCfg[0].astWndCfg[0].stWndAttr.stRect.u32Width * 2;
#else
    /* software decode JPEG needs one block of big VB in CommPool[0] */
    pstMediaCfg->stVBCfg.u32MaxPoolCnt = 2;
    pstMediaCfg->stVBCfg.astCommPool[1].u32BlkCnt = 5;
    pstMediaCfg->stVBCfg.astCommPool[1].u32BlkSize = pstMediaCfg->stVideoOutCfg.astDispCfg[0].astWndCfg[0].stWndAttr.stRect.u32Height *
        pstMediaCfg->stVideoOutCfg.astDispCfg[0].astWndCfg[0].stWndAttr.stRect.u32Width * 2;
#endif

    /** change venccfg*/
    for (i = 0; i < HI_PDT_MEDIA_VENC_MAX_CNT; i++)
    {
        pstMediaCfg->stVideoCfg.astVencCfg[i].bEnable = HI_FALSE;
    }

    HI_PDT_MEDIA_AO_CFG_S* pstAoCfg = &(pstMediaCfg->stAudioOutCfg.astAoCfg[0]);
    pstAoCfg->AoHdl = pstPlayBackCfg->stAoutOpt.hAudTrackHdl;

    for(i = 0; i < HI_PDT_MEDIA_AENC_MAX_CNT; i++)
    {
        pstMediaCfg->stAudioCfg.astAencCfg[i].bEnable = HI_FALSE;
    }
    /** change osd*/
    pstMediaCfg->stVideoCfg.stOsdCfg.s32OsdCnt = 0;
}

/** enter Playback state */
HI_S32 PDT_STATEMNG_PlaybackStateEnter(HI_VOID *pvArg)
{
    HI_S32 s32Ret = HI_SUCCESS;
    PDT_STATEMNG_CONTEXT *pstStateMngCtx = PDT_STATEMNG_GetCtx();

    /** check parameters */
    PDT_STATEMNG_CHECK_POINTER(pvArg,HI_PDT_STATEMNG_ENULLPTR,"parameter pvArg error");

    PDT_STATEMNG_STATE_ATTR_S *pstStateAttr = (PDT_STATEMNG_STATE_ATTR_S *)pvArg;
    MLOGD(YELLOW"try to enter state(%s), bRunning(%d)\n\n"NONE,
                pstStateAttr->stState.name, (pstStateAttr->bRunning));

    /** get enter workmode and check it */
    HI_PDT_WORKMODE_E enEnterWorkMode = HI_PDT_WORKMODE_BUTT;
    s32Ret = PDT_STATEMNG_State2WorkMode(pstStateAttr->stState.name, &enEnterWorkMode);
    PDT_STATEMNG_CHECK_RET(s32Ret,HI_STORAGEMNG_EINTER,"change state to workmode");
    if(HI_PDT_WORKMODE_PLAYBACK != enEnterWorkMode)
    {
        MLOGE(RED"enter workmode[%d] error\n\n"NONE,enEnterWorkMode);
        return HI_PDT_STATEMNG_EINVAL;
    }
    else
    {
        pstStateMngCtx->enCurrentWorkMode = enEnterWorkMode;
        pstStateMngCtx->bRunning = pstStateAttr->bRunning;
    }
    /*get media mode config*/
    s32Ret = PDT_STATEMNG_GetMediaModeCfg(pstStateMngCtx->enCurrentWorkMode,pstStateMngCtx->astCamCtx);
    PDT_STATEMNG_CHECK_RET(s32Ret,s32Ret,"get media mode config");


    /** get media config from Param module */
    HI_PDT_MEDIA_CFG_S stEnterMediaCfg;
    s32Ret = HI_PDT_PARAM_GetMediaCfg(enEnterWorkMode, pstStateMngCtx->astCamCtx,&stEnterMediaCfg);
    PDT_STATEMNG_CHECK_RET(s32Ret, HI_PDT_STATEMNG_EINTER, "get media config");

    /**update disp configure*/
    s32Ret = PDT_STATEMNG_UpdateDispCfg(&stEnterMediaCfg);
    PDT_STATEMNG_CHECK_RET(s32Ret,HI_PDT_STATEMNG_EINTER,"update video out configure");

    /** generate MediaCfg */
    PDT_STATEMNG_MediaCfgResetForPlayback(&stEnterMediaCfg);

    /** reset Media */
    s32Ret = PDT_STATEMNG_ResetMedia(&stEnterMediaCfg);
    PDT_STATEMNG_CHECK_RET(s32Ret,HI_STORAGEMNG_EINTER,"reset media");

    /** publish HI_EVENT_STATEMNG_SWITCH_WORKMODE event to EventHub */
    HI_EVENT_S stEvent;
    memset(&stEvent, 0 , sizeof(HI_EVENT_S));
    stEvent.EventID = HI_EVENT_STATEMNG_SWITCH_WORKMODE;
    stEvent.arg2 = enEnterWorkMode;
    stEvent.s32Result = HI_SUCCESS;
    MUTEX_LOCK(pstStateMngCtx->Mutex);
    pstStateMngCtx->bInProgress = HI_FALSE;
    MUTEX_UNLOCK(pstStateMngCtx->Mutex);

    s32Ret = HI_EVTHUB_Publish(&stEvent);
    if(HI_SUCCESS != s32Ret)
    {
        MLOGE(RED"publish HI_EVENT_STATEMNG_SWITCH_WORKMODE event failed\n\n"NONE);
        return HI_FAILURE;
    }
    else
    {
        MLOGD(YELLOW"publish event:HI_EVENT_STATEMNG_SWITCH_WORKMODE(%x), "
                    "arg2(%s) to EventHub succeed\n\n"NONE,
                    stEvent.EventID, pstStateAttr->stState.name);
    }

    HI_TIME_STAMP;
    return s32Ret;
}

/** exit Playback state */
HI_S32 PDT_STATEMNG_PlaybackStateExit(HI_VOID *pvArg)
{
    /** check parameters */
    PDT_STATEMNG_CHECK_POINTER(pvArg,HI_PDT_STATEMNG_ENULLPTR,"parameter pvArg error");

    PDT_STATEMNG_STATE_ATTR_S *pstStateAttr = (PDT_STATEMNG_STATE_ATTR_S *)pvArg;
    MLOGD(YELLOW"exit state(%s), bRunning(%d)\n\n"NONE,
                pstStateAttr->stState.name, (pstStateAttr->bRunning));

    return HI_SUCCESS;
}

/** Playback state message process */
HI_S32 PDT_STATEMNG_PlaybackStateMsgProc(HI_MESSAGE_S *pstMsg,
                                         HI_VOID *pvArg,
                                         HI_STATE_ID *pStateID)
{
    HI_S32 s32Ret = HI_SUCCESS;
    PDT_STATEMNG_CONTEXT *pstStateMngCtx = PDT_STATEMNG_GetCtx();
    /** check parameters */
    PDT_STATEMNG_CHECK_MSGPROC_FUNC_PARAM(pvArg, pStateID, pstMsg,
                                          pstStateMngCtx->bInProgress);

    PDT_STATEMNG_STATE_ATTR_S *pstStateAttr = (PDT_STATEMNG_STATE_ATTR_S *)pvArg;
    MLOGD("current state(%s), bRunning(%d)\n\n",
          pstStateAttr->stState.name, (pstStateAttr->bRunning));

    HI_PDT_WORKMODE_E enCurrentWorkMode = HI_PDT_WORKMODE_BUTT;
    s32Ret = PDT_STATEMNG_State2WorkMode(pstStateAttr->stState.name, &enCurrentWorkMode);
    PDT_STATEMNG_CHECK_RET(s32Ret,HI_STORAGEMNG_EINTER,"change state to workmode");

    switch(pstMsg->what)
    {
        case HI_EVENT_STATEMNG_START:
        case HI_EVENT_STATEMNG_STOP:
        case HI_EVENT_STATEMNG_TRIGGER:
        case HI_EVENT_STATEMNG_SETTING:
        case HI_EVENT_STATEMNG_LIVE_SWITCH:
        case HI_EVENT_STATEMNG_VO_SWITCH:
        {
            MLOGD(YELLOW"no need to process message what(%x)\n\n"NONE,
                        pstMsg->what);
            MUTEX_LOCK(pstStateMngCtx->Mutex);
            pstStateMngCtx->bInProgress = HI_FALSE;
            MUTEX_UNLOCK(pstStateMngCtx->Mutex);
            PDT_STATEMNG_PublishEvent(pstMsg, HI_SUCCESS);
            return HI_PROCESS_MSG_RESULTE_OK;
        }
        case HI_EVENT_RECMNG_ERROR:
        case HI_EVENT_FILEMNG_SPACE_FULL:
        {
            MLOGD(YELLOW"no need to process message what(%x)\n\n"NONE,
                        pstMsg->what);
            return HI_PROCESS_MSG_RESULTE_OK;
        }
#ifdef CONFIG_USB_HOST_UVC_SUPPORT
        case HI_EVENT_STATEMNG_HOSTUVC_START:
            {
                MLOGD("###res--> width:[%d],hight:[%d]\n",pstMsg->arg1,pstMsg->arg2);
                PDT_STATEMNG_StartHostUvc(pstMsg->arg1, pstMsg->arg2);
                PDT_STATEMNG_UPDATESTATUS(pstMsg, HI_SUCCESS, HI_FALSE);
                return HI_PROCESS_MSG_RESULTE_OK;
            }
        case HI_EVENT_STATEMNG_HOSTUVC_STOP:
            {
                MLOGD("#################host uvc stop!!\n");
                PDT_STATEMNG_StopHostUvc();
                PDT_STATEMNG_UPDATESTATUS(pstMsg, HI_SUCCESS, HI_FALSE);
                return HI_PROCESS_MSG_RESULTE_OK;
            }
#endif

        /** need base state process */
        case HI_EVENT_STORAGEMNG_DEV_UNPLUGED:
        case HI_EVENT_STATEMNG_POWEROFF:
        default:
        {
            MLOGD(YELLOW"can not process this message, upload it to Base state\n\n"NONE);
            return HI_PROCESS_MSG_UNHANDLER;/** need base state precess */
        }
    }

    return HI_PROCESS_MSG_RESULTE_OK;
}

/** init Playback state, add Playback state to HFSM */
HI_S32 PDT_STATEMNG_PlaybackStateInit(const PDT_STATEMNG_STATE_ATTR_S* pstBase)
{
    HI_S32 s32Ret = HI_SUCCESS;

    static PDT_STATEMNG_STATE_ATTR_S stPlaybackState =
        {{HI_PDT_WORKMODE_PLAYBACK,
          PDT_STATEMNG_STATE_PLAYBACK,
          PDT_STATEMNG_PlaybackStateEnter,
          PDT_STATEMNG_PlaybackStateExit,
          PDT_STATEMNG_PlaybackStateMsgProc,
          NULL},HI_FALSE};
    stPlaybackState.stState.argv = &stPlaybackState;
    s32Ret = HI_HFSM_AddState(PDT_STATEMNG_GetCtx()->pvHfsmHdl,
                              &stPlaybackState.stState,
                              (HI_STATE_S*)&(pstBase->stState));
    PDT_STATEMNG_CHECK_RET(s32Ret,HI_STORAGEMNG_EINTER,"HFSM add Playback state");

    return s32Ret;
}

/** deinit Playback State module */
HI_S32 PDT_STATEMNG_PlaybackStateDeinit()
{
    return HI_SUCCESS;
}

#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */


